// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module A_cse_ocs_dpa_aes10c_gf16_sq_sbox_masked_withmap
    #( parameter OCS_AES_DPA_USE_CTECH = 1
     )
    (
	input logic encrypt,
	input logic [7:0] in,
	input logic [7:0] in_mask,
	input logic [7:0] out_mask,
	output logic [7:0] out	
	);

	// Local params
	localparam POLY1 = 9;
   	localparam ALPHA = 1;
   	localparam BETA = 8;
	
	localparam MAP_ROW7 = 8'b11010010;
   	localparam MAP_ROW6 = 8'b01111110;
   	localparam MAP_ROW5 = 8'b00001100;
   	localparam MAP_ROW4 = 8'b11010000;
   	localparam MAP_ROW3 = 8'b00001000;
   	localparam MAP_ROW2 = 8'b00100100;
   	localparam MAP_ROW1 = 8'b11100110;
   	localparam MAP_ROW0 = 8'b11000111;

	localparam COMBINEDINVAFFINE_MAP_ROW7 = 8'b01111000;
	localparam COMBINEDINVAFFINE_MAP_ROW6 = 8'b00001001;
	localparam COMBINEDINVAFFINE_MAP_ROW5 = 8'b10110111;
	localparam COMBINEDINVAFFINE_MAP_ROW4 = 8'b00110001;
	localparam COMBINEDINVAFFINE_MAP_ROW3 = 8'b00100101;
	localparam COMBINEDINVAFFINE_MAP_ROW2 = 8'b00000110;
	localparam COMBINEDINVAFFINE_MAP_ROW1 = 8'b00110100;
	localparam COMBINEDINVAFFINE_MAP_ROW0 = 8'b00000100;
	localparam INVAFFINE_MB = 8'b01100110;

	localparam INVAFF_MAP_ROW7 = 8'b01011000;
      	localparam INVAFF_MAP_ROW6 = 8'b11110001;
        localparam INVAFF_MAP_ROW5 = 8'b01110010;
        localparam INVAFF_MAP_ROW4 = 8'b01100111;
        localparam INVAFF_MAP_ROW3 = 8'b00010110;
      	localparam INVAFF_MAP_ROW2 = 8'b11111100;
      	localparam INVAFF_MAP_ROW1 = 8'b11000100;
      	localparam INVAFF_MAP_ROW0 = 8'b11111001;
      	localparam MA_INV_B = 8'b01000010;

	localparam COMBINEDAFFINE_MAP_ROW7 = 8'b00110100;
	localparam COMBINEDAFFINE_MAP_ROW6 = 8'b11010000;
	localparam COMBINEDAFFINE_MAP_ROW5 = 8'b00011010;
	localparam COMBINEDAFFINE_MAP_ROW4 = 8'b00011001;
	localparam COMBINEDAFFINE_MAP_ROW3 = 8'b01010011;
	localparam COMBINEDAFFINE_MAP_ROW2 = 8'b00000001;
	localparam COMBINEDAFFINE_MAP_ROW1 = 8'b00000101;
	localparam COMBINEDAFFINE_MAP_ROW0 = 8'b00010011;
	localparam AFFINE_B = 8'b01100011;
	
	// Wires
	wire [7:0] map_mask_in, map_mask_out;
	wire [7:0] invaff_map_mask_in, invaff_map_mask_out;
	wire [7:0] sbox_out_encrypt, sbox_out_decrypt;
	wire [7:0] inv_in, inv_mask_in;
	wire [7:0] inv_out, inv_mask_out;
	wire [7:0] map_out_encrypt, map_out_decrypt;

	// Map the data to the GF(16)^2 field for encrypt
	A_cse_ocs_dpa_aes10c_map #(
                   .MAP_ROW7(MAP_ROW7 ),
                   .MAP_ROW6(MAP_ROW6 ),
                   .MAP_ROW5(MAP_ROW5 ),
                   .MAP_ROW4(MAP_ROW4 ),
                   .MAP_ROW3(MAP_ROW3 ),
                   .MAP_ROW2(MAP_ROW2 ),
                   .MAP_ROW1(MAP_ROW1 ),
                   .MAP_ROW0(MAP_ROW0 ))
           	map_encrypt ( .in(in), .out(map_out_encrypt));

	// Combined Map and Inv-affine on data for decrypt
	A_cse_ocs_dpa_aes10c_inv_affine #(
                   .INVAFF_MAP_ROW7(COMBINEDINVAFFINE_MAP_ROW7 ),
                   .INVAFF_MAP_ROW6(COMBINEDINVAFFINE_MAP_ROW6 ),
                   .INVAFF_MAP_ROW5(COMBINEDINVAFFINE_MAP_ROW5 ),
                   .INVAFF_MAP_ROW4(COMBINEDINVAFFINE_MAP_ROW4 ),
                   .INVAFF_MAP_ROW3(COMBINEDINVAFFINE_MAP_ROW3 ),
                   .INVAFF_MAP_ROW2(COMBINEDINVAFFINE_MAP_ROW2 ),
                   .INVAFF_MAP_ROW1(COMBINEDINVAFFINE_MAP_ROW1 ),
                   .INVAFF_MAP_ROW0(COMBINEDINVAFFINE_MAP_ROW0 ),
                   .MA_INV_B(INVAFFINE_MB))
		map_decrypt ( .in(in), .out(map_out_decrypt));

	// Generate the appropriate input and output masks 
	// to compensate for affine/inv-affine transformations

	assign map_mask_in = (encrypt) ? in_mask : out_mask;

	A_cse_ocs_dpa_aes10c_map #(
                   .MAP_ROW7(MAP_ROW7 ),
                   .MAP_ROW6(MAP_ROW6 ),
                   .MAP_ROW5(MAP_ROW5 ),
                   .MAP_ROW4(MAP_ROW4 ),
                   .MAP_ROW3(MAP_ROW3 ),
                   .MAP_ROW2(MAP_ROW2 ),
                   .MAP_ROW1(MAP_ROW1 ),
                   .MAP_ROW0(MAP_ROW0 ))
                map_mask ( .in(map_mask_in), .out(map_mask_out));

	assign invaff_map_mask_in = (encrypt) ? out_mask : in_mask;

	A_cse_ocs_dpa_aes10c_inv_affine #(                   
		   .INVAFF_MAP_ROW7(COMBINEDINVAFFINE_MAP_ROW7 ),
                   .INVAFF_MAP_ROW6(COMBINEDINVAFFINE_MAP_ROW6 ),
                   .INVAFF_MAP_ROW5(COMBINEDINVAFFINE_MAP_ROW5 ),
                   .INVAFF_MAP_ROW4(COMBINEDINVAFFINE_MAP_ROW4 ),
                   .INVAFF_MAP_ROW3(COMBINEDINVAFFINE_MAP_ROW3 ),
                   .INVAFF_MAP_ROW2(COMBINEDINVAFFINE_MAP_ROW2 ),
                   .INVAFF_MAP_ROW1(COMBINEDINVAFFINE_MAP_ROW1 ),
                   .INVAFF_MAP_ROW0(COMBINEDINVAFFINE_MAP_ROW0 ),
                   .MA_INV_B(8'h00))
                invaff_map_mask ( .in(invaff_map_mask_in), .out(invaff_map_mask_out));

	//Mux to choose correct inputs for encrypt/decrypt datapath
	assign inv_in 		= 	(encrypt == 1'b1) ? map_out_encrypt : map_out_decrypt;
	assign inv_mask_in 	= 	(encrypt == 1'b1) ? map_mask_out : invaff_map_mask_out;
	assign inv_mask_out 	=	(encrypt == 1'b1) ? invaff_map_mask_out : map_mask_out;

	// GF(16)^2 inverse computation
	A_cse_ocs_dpa_aes10c_gf16_sq_inv_masked #(
                    .OCS_AES_DPA_USE_CTECH(OCS_AES_DPA_USE_CTECH),
		    .BETA(BETA ),
		    .ALPHA(ALPHA ),
		    .POLY1(POLY1 ))
		  gf256_inv ( .a(inv_in), .a_mask(inv_mask_in), .o_mask(inv_mask_out), .o(inv_out) );

	// Combined inverse-affine and map for encrypt
	A_cse_ocs_dpa_aes10c_affine #(
		  .AFFINE_MAP_ROW7(COMBINEDAFFINE_MAP_ROW7),
		  .AFFINE_MAP_ROW6(COMBINEDAFFINE_MAP_ROW6),
		  .AFFINE_MAP_ROW5(COMBINEDAFFINE_MAP_ROW5),
		  .AFFINE_MAP_ROW4(COMBINEDAFFINE_MAP_ROW4),
		  .AFFINE_MAP_ROW3(COMBINEDAFFINE_MAP_ROW3),
		  .AFFINE_MAP_ROW2(COMBINEDAFFINE_MAP_ROW2),
		  .AFFINE_MAP_ROW1(COMBINEDAFFINE_MAP_ROW1),
		  .AFFINE_MAP_ROW0(COMBINEDAFFINE_MAP_ROW0),
		  .MB(AFFINE_B))
		 inv_map_encrypt ( .in(inv_out), .out(sbox_out_encrypt) );

	// Inverse-map for decrypt
	A_cse_ocs_dpa_aes10c_map_top inv_map_decrypt ( .in(inv_out), .out(sbox_out_decrypt));

	assign out = (encrypt == 1'b1) ? sbox_out_encrypt : sbox_out_decrypt;

endmodule
